package com.cheer.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.cheer.common.Page;
import com.cheer.dao.*;
import com.cheer.dto.UserItem;
import com.cheer.entity.*;
import com.cheer.exception.ServiceException;
import com.cheer.service.ExPresentAudioAdminService;
import com.cheer.service.OaLearnClassService;
import com.cheer.service.OaUserService;
import com.cheer.vo.*;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class ExPresentAudioServiceAdminImpl implements ExPresentAudioAdminService {

    @Autowired
    private ExPresentAudioCountDao exPresentAudioCountDao;

    @Autowired
    private ExPresentAudioDao exPresentAudioDao;

    @Autowired
    private ExPresentAudioGoodDao exPresentAudioGoodDao;

    @Autowired
    private OaLearnClassDao oaLearnClassDao;

    @Autowired
    private OaUserDao oaUserDao;

    @Autowired
    private OaLearnClassService oaLearnClassService;

    @Override
    public ExPresentAudioStatisticsAdminVO getStatistics(Integer id) {
        OaLearnClassEntity entity = oaLearnClassDao.selectById(id);
        if (entity == null && id != 0) {
            return null;
        }
        String path = (id == 0) ? "0," : entity.getPath() + entity.getId() + ",";
        return new ExPresentAudioStatisticsAdminVO().setTotalCount(exPresentAudioDao.countByPathTotal(path))
                .setTotalUserCount(exPresentAudioDao.countByPath(path))
                .setGoodUserCount(exPresentAudioGoodDao.countByPathTotal(path))
                .setUnreviewCount(exPresentAudioDao.countByPathUnreview(path));
    }

    @Override
    public Page<ExPresentAudioLearnClassVO> list(Integer pageNum, Integer pageSize, Integer learnClassId) {
        Page<OaLearnClassListVO> page = oaLearnClassService.list(pageNum, pageSize, learnClassId);
        List<ExPresentAudioLearnClassVO> list = page.getContent().stream()
                .map(oaLearnClassListVO -> {
                    ExPresentAudioLearnClassVO exPresentAudioLearnClassVO = new ExPresentAudioLearnClassVO();
                    exPresentAudioLearnClassVO.setId(oaLearnClassListVO.getId());
                    exPresentAudioLearnClassVO.setName(oaLearnClassListVO.getName());
                    exPresentAudioLearnClassVO.setPname(oaLearnClassListVO.getPname());
                    exPresentAudioLearnClassVO.setNum(exPresentAudioDao.countByPath(oaLearnClassListVO.getPath()));
                    exPresentAudioLearnClassVO.setGoodNum(exPresentAudioGoodDao.countByPath(oaLearnClassListVO.getPath()));
                    return exPresentAudioLearnClassVO;
                })
                .collect(Collectors.toList());
        Page<ExPresentAudioLearnClassVO> returnPage = new Page<>();
        returnPage.setPageNum(page.getPageNum());
        returnPage.setPageSize(page.getPageSize());
        returnPage.setContent(list);
        returnPage.setTotal(page.getTotal());
        returnPage.setPages(page.getPages());
        return returnPage;
    }

    @Override
    public ExPresentAudioLearnClassInfoVO info(Integer id) {
        OaLearnClassEntity entity = oaLearnClassDao.selectById(id);
        if (entity == null) {
            return null;
        }
        ExPresentAudioLearnClassInfoVO vo = new ExPresentAudioLearnClassInfoVO();
        vo.setId(entity.getId());
        vo.setName(entity.getName());

        Set<String> idSet = new HashSet<>();
        String[] split = StringUtils.split(entity.getPath(), ",");
        idSet.addAll(Lists.newArrayList(split));
        idSet.remove("0");

        Map<Integer, String> map = new HashMap<>();
        map.put(0, "顶级");

        if (CollectionUtils.isNotEmpty(idSet)) {
            List<Integer> ids = idSet.stream()
                    .map(Integer::valueOf)
                    .collect(Collectors.toList());
            List<OaLearnClassEntity> learnClassList = oaLearnClassDao.selectBatchIds(ids);
            learnClassList.forEach(learnClass -> {
                map.put(learnClass.getId(), learnClass.getName());
            });
        }

        if (split.length == 1 && split[0].equals("0")) {
            vo.setPname("顶级");
        } else {
            List<String> pLearnClass = new ArrayList<>();
            for (String str : split) {
                if (!str.equals("0")) {
                    String pClass = map.get(Integer.valueOf(str));
                    if (pClass != null) {
                        pLearnClass.add(pClass);
                    }
                }
            }
            vo.setPname(StringUtils.join(pLearnClass, "-"));
        }

        vo.setTotal(exPresentAudioDao.countByPathTotal(entity.getPath() + entity.getId() + ","));
        vo.setTotalUser(exPresentAudioDao.countByPath(entity.getPath() + entity.getId() + ","));
        vo.setGoodUser(exPresentAudioGoodDao.countByPath(entity.getPath() + entity.getId() + ","));

        return vo;
    }

    @Override
    public Page<ExPresentAudioUserVO> userList(Integer pageNum, Integer pageSize, Integer id, String name) {
        OaLearnClassEntity entity = oaLearnClassDao.selectById(id);
        if (entity == null) {
            return null;
        }
        String path = entity.getPath() + entity.getId() + ",";

        name = StringUtils.trimToNull(name);

        PageHelper.startPage(pageNum, pageSize);
        List<ExPresentAudioUserVO> list = exPresentAudioDao.selectByUser(path, name);
        PageInfo<ExPresentAudioUserVO> pageInfo = new PageInfo<>(list);

        for (ExPresentAudioUserVO vo : pageInfo.getList()) {
            List<ExPresentAudioEntity> audioList = exPresentAudioDao.selectByUserId(vo.getId());
            vo.setUnReviewed((int) audioList.stream().filter(audio -> audio.getStatus() == 1).count());
            vo.setGoodCount((int) audioList.stream().filter(audio -> audio.getStatus() == 3).count());
        }

        return new Page<ExPresentAudioUserVO>()
                .setPageNum(pageInfo.getPageNum())
                .setPageSize(pageInfo.getPageSize())
                .setPages(pageInfo.getPages())
                .setTotal(pageInfo.getTotal())
                .setContent(list);

    }

    @Override
    @Transactional
    public void delete(Integer id) {
        int delete = exPresentAudioDao.deleteByUserId(id);
        int deleteGood = exPresentAudioGoodDao.deleteByUserId(id);

        if (delete > 0 || deleteGood > 0) {
            exPresentAudioCountDao.decr(delete > 0 ? delete : null, delete > 0 ? 1 : null,
                    deleteGood > 0 ? deleteGood : null, deleteGood > 0 ? 1 : null);
        }
    }

    @Autowired
    private OaUserService oaUserService;

    @Override
    public ExPresentAudioUserAdminVO user(Integer id) {
        OaUserInfoVO user = oaUserService.info(id);
        if (user == null) {
            return null;
        }

        ExPresentAudioUserAdminVO exPresentAudioUserAdminVO = new ExPresentAudioUserAdminVO();
        exPresentAudioUserAdminVO.setId(user.getId());
        exPresentAudioUserAdminVO.setName(user.getName());
        exPresentAudioUserAdminVO.setLearnClass(user.getLearnClass());
        exPresentAudioUserAdminVO.setHeadUrl(user.getHeadImgUrl());

        exPresentAudioUserAdminVO.setVoteCount(exPresentAudioDao.sumOfVote(id));
        return exPresentAudioUserAdminVO;
    }

    @Value("${audio.url}")
    private String audioUrl;

    @Override
    public Page<ExPresentAudioAdminVO> audio(Integer pageNum, Integer pageSize, Integer id) {
        IPage<ExPresentAudioEntity> page = exPresentAudioDao.selectPageByUserId(pageNum, pageSize, id);

        List<ExPresentAudioAdminVO> list = page.getRecords().stream().map(exPresentAudioEntity -> new ExPresentAudioAdminVO()
                .setId(exPresentAudioEntity.getId())
                .setAudioUrl(audioUrl + exPresentAudioEntity.getUrl())
                .setStatus(exPresentAudioEntity.getStatus())
                .setCreateTime(DateUtil.format(exPresentAudioEntity.getCreateTime(),
                        DatePattern.NORM_DATETIME_MINUTE_FORMAT))).collect(Collectors.toList());

        return new Page<>(page, list);
    }

    @Override
    @Transactional
    public void deleteAudio(Integer id) {
        ExPresentAudioEntity audio = exPresentAudioDao.selectById(id);
        if (audio == null) {
            return;
        }

        int delete = exPresentAudioDao.deleteById(id);
        int deleteGood = exPresentAudioGoodDao.deleteById(id);

        List<ExPresentAudioEntity> audioList = exPresentAudioDao.selectByUserId(audio.getUserId());

        int deleteUser = 0;
        if (delete > 0 && audioList.size() == 0) {
            deleteUser = 1;
        }

        int deleteUserGood = 0;
        if (deleteGood > 0 && audioList.stream().noneMatch(e -> e.getStatus() == 3)) {
            deleteUserGood = 1;
        }

        if (delete > 0 || deleteGood > 0) {
            exPresentAudioCountDao.decr(delete > 0 ? delete : null, deleteUser > 0 ? 1 : null,
                    deleteGood > 0 ? deleteGood : null, deleteUserGood > 0 ? 1 : null);
        }
    }

    @Override
    @Transactional
    public void review(Integer id, Integer status) {
        ExPresentAudioEntity audio = exPresentAudioDao.selectById(id);
        if (audio == null) {
            return;
        }

        ExPresentAudioEntity exPresentAudioEntity = new ExPresentAudioEntity();
        exPresentAudioEntity.setId(id);
        exPresentAudioEntity.setStatus(status);
        int update = exPresentAudioDao.updateById(exPresentAudioEntity);
        if (update == 0) {
            return;
        }

        List<ExPresentAudioEntity> audioList = exPresentAudioDao.selectByUserId(audio.getUserId());

        int good = 0;
        int goodUser = 0;

        if (status == 3) {
            good = -1;
            if (audioList.stream().filter(e -> e.getStatus() == 3).count() == 1) {
                goodUser = -1;
            }
            ExPresentAudioGoodEntity goodEntity = new ExPresentAudioGoodEntity();
            goodEntity.setId(audio.getId())
                    .setUserId(audio.getUserId())
                    .setType(audio.getType())
                    .setUrl(audio.getUrl())
                    .setCreateTime(audio.getCreateTime())
                    .setDepartment(audio.getDepartment())
                    .setPath(audio.getPath())
                    .setVote(audio.getVote());
            exPresentAudioGoodDao.insert(goodEntity);
        }
        if (audio.getStatus() == 3 && status == 2) {
            good = 1;
            if (audioList.stream().noneMatch(e -> e.getStatus() == 3)) {
                goodUser = 1;
            }
            exPresentAudioGoodDao.deleteById(id);
        }

        if (good != 0) {
            exPresentAudioCountDao.decr(null, null, good, goodUser != 0 ? goodUser : null);
        }
    }

    @Override
    public ExPresentAudioAdminVO audioInfo(Integer id) {
        ExPresentAudioEntity entity = exPresentAudioDao.selectById(id);
        if (entity == null) {
            return null;
        }
        ExPresentAudioAdminVO vo = new ExPresentAudioAdminVO();
        vo.setId(entity.getId());
        vo.setAudioUrl(audioUrl + entity.getUrl());
        vo.setStatus(entity.getStatus());
        ExPresentAudioEntity next = exPresentAudioDao.selectNext(id, entity.getUserId());
        if (next != null) {
            vo.setNext(next.getId());
        }
        ExPresentAudioEntity prev = exPresentAudioDao.selectPrev(id, entity.getUserId());
        if (prev != null) {
            vo.setPrev(prev.getId());
        }
        return vo;
    }

    @Override
    public Page<ExPresentAudioAdminVO> unreviewList(Integer pageNum, Integer pageSize, Integer pid) {
        OaLearnClassEntity entity = oaLearnClassDao.selectById(pid);
        if (entity == null && pid != 0) {
            return null;
        }
        String path = (pid == 0) ? "0," : entity.getPath() + entity.getId() + ",";
        IPage<ExPresentAudioEntity> page = exPresentAudioDao.selectPageByStatus(pageNum, pageSize, path);

        List<Integer> userIds = page.getRecords().stream().map(ExPresentAudioGoodEntity::getUserId).collect(Collectors.toList());
        List<UserItem> users = listUserItems(userIds);
        Map<Integer, UserItem> userMap = users.stream().collect(Collectors.toMap(UserItem::getId, Function.identity()));

        List<ExPresentAudioAdminVO> list = page.getRecords().stream().map(exPresentAudioGoodEntity -> {
            UserItem userItem = userMap.get(exPresentAudioGoodEntity.getUserId());
            if (userItem == null) {
                return null;
            }
            ExPresentAudioAdminVO exPresentAudioVO = new ExPresentAudioAdminVO();
            exPresentAudioVO.setId(exPresentAudioGoodEntity.getId());
            exPresentAudioVO.setName(userItem.getName());
            exPresentAudioVO.setAudioUrl(exPresentAudioGoodEntity.getUrl());
            exPresentAudioVO.setLearnClass(userItem.getDepartment());
            exPresentAudioVO.setStatus(exPresentAudioGoodEntity.getStatus());
            exPresentAudioVO.setCreateTime(DateUtil.format(exPresentAudioGoodEntity.getCreateTime(),
                    DatePattern.NORM_DATETIME_MINUTE_FORMAT));
            return exPresentAudioVO;
        }).filter(Objects::nonNull).collect(Collectors.toList());

        return new Page<>(page, list);
    }

    @Override
    public ExPresentAudioAdminVO unreviewInfo(Integer id) {
        ExPresentAudioEntity entity = exPresentAudioDao.selectById(id);
        if (entity == null) {
            return null;
        }
        ExPresentAudioAdminVO vo = new ExPresentAudioAdminVO();
        vo.setId(entity.getId());
        vo.setAudioUrl(audioUrl + entity.getUrl());
        vo.setStatus(entity.getStatus());
        ExPresentAudioEntity next = exPresentAudioDao.selectNextUnreview(id);
        if (next != null) {
            vo.setNext(next.getId());
        }
        ExPresentAudioEntity prev = exPresentAudioDao.selectPrevUnreview(id);
        if (prev != null) {
            vo.setPrev(prev.getId());
        }
        return vo;
    }

    private List<UserItem> listUserItems(List<Integer> userIds) {
        if (CollectionUtils.isEmpty(userIds)) {
            return new ArrayList<>();
        }

        List<OaUserEntity> users = oaUserDao.selectBatchIds(userIds);
        if (CollectionUtils.isEmpty(users)) {
            return new ArrayList<>();
        }

        Map<Integer, String> departmentMap = extractDepartmentMap(users);

        return users.stream()
                .map(user -> buildFromUser(user, departmentMap))
                .collect(Collectors.toList());
    }

    private Map<Integer, String> extractDepartmentMap(List<OaUserEntity> users) {
        List<Integer> departmentIds = users.stream()
                .map(OaUserEntity::getPath)
                .flatMap(departmentPath -> Arrays.stream(StringUtils.split(departmentPath, ",")))
                .distinct()
                .map(Integer::valueOf)
                .filter(departmentId -> departmentId != 0)
                .collect(Collectors.toList());

        if (CollectionUtils.isEmpty(departmentIds)) {
            return new HashMap<>();
        }

        return oaLearnClassDao.selectBatchIds(departmentIds).stream()
                .collect(Collectors.toMap(OaLearnClassEntity::getId, OaLearnClassEntity::getName));
    }

    private UserItem buildFromUser(OaUserEntity user, Map<Integer, String> departmentMap) {
        UserItem userItemResponse = new UserItem();
        BeanUtils.copyProperties(user, userItemResponse);
        userItemResponse.setHeadImgUrl(user.getHeadimgurl());

        String department = Arrays.stream(StringUtils.split(user.getPath(), ","))
                .map(Integer::valueOf)
                .filter(departmentId -> departmentId != 0)
                .map(departmentMap::get)
                .filter(Objects::nonNull)
                .collect(Collectors.joining("-"));
        userItemResponse.setDepartment(department);

        return userItemResponse;
    }
}